/*
 * Copyright (c) 2008, Roman Bosak
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the DailyDevelopment nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.atlassian.jira.web.action.portal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;

import com.atlassian.jira.portal.PortalManager;
import com.atlassian.jira.portal.PortalPageConfiguration;
import com.atlassian.jira.portal.PortletConfigurationException;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.util.EmailFormatter;
import com.atlassian.jira.util.GroupPermissionChecker;
import com.atlassian.jira.web.action.user.ConfigurePortalPages;
import com.dailydev.jira.portal.IDashboardSharingPortalManager;
import com.dailydev.jira.portal.config.IPortalPageSharingConfiguration;
import com.dailydev.jira.portal.config.ISharedPortalPage;
import com.opensymphony.user.EntityNotFoundException;
import com.opensymphony.user.User;
import com.opensymphony.user.UserManager;

/**
 * Webwork action extending standard Jira {@link ConfigurePortalPages} action
 * with additional functionalities related to portal page sharing.
 * 
 * @author Roman Bosak, roman.bosak@gmail.com
 */
public class ConfigureSharedPortalPages extends ConfigurePortalPages {

    /**
     * Constant for error message shown by this action when it is unable to get
     * shared portal pages.
     */
    protected static final String UNABLE_TO_GET_SHARED_PORTAL_PAGES = "Unable to get shared portal pages.";

    /**
     * Constant for error message shown by this action when it is unable to get
     * own portal pages.
     */
    protected static final String UNABLE_TO_GET_OWN_PORTAL_PAGES = "Unable to get own portal pages.";

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 6909283026754315384L;

    /**
     * Logger for this class.
     */
    private static final Logger LOG = Logger
            .getLogger(ConfigureSharedPortalPages.class);

    /**
     * Reference to {@link IDashboardSharingPortalManager} instance.
     */
    private final transient IDashboardSharingPortalManager portalManager;

    /**
     * Reference to {@link UserManager} instance.
     */
    private final UserManager userManager;

    /**
     * Reference to configuration of portal page sharing.
     */
    private final transient IPortalPageSharingConfiguration configuration;

    /**
     * Constructor for {@link ConfigureSharedPortalPages}.
     * 
     * @param portalMgr
     *            reference to {@link IDashboardSharingPortalManager} instance
     *            provided by Jira
     * @param authenticationContext
     *            reference to {@link JiraAuthenticationContext} instance
     *            provided by Jira
     * @param userMgr
     *            reference to {@link UserManager} instance provided by Jira
     * @param sharingConfig
     *            reference to {@link IPortalPageSharingConfiguration}
     *            propagated from Jira
     */
    public ConfigureSharedPortalPages(
            final IDashboardSharingPortalManager portalMgr,
            final JiraAuthenticationContext authenticationContext,
            final UserManager userMgr,
            final IPortalPageSharingConfiguration sharingConfig) {
        super(portalMgr, authenticationContext);
        this.portalManager = portalMgr;
        this.userManager = userMgr;
        this.configuration = sharingConfig;
    }

    /**
     * Constructor for {@link ConfigureSharedPortalPages}.
     * 
     * @param portalMgr
     *            reference to {@link IDashboardSharingPortalManager} instance
     *            provided by Jira
     * @param authenticationContext
     *            reference to {@link JiraAuthenticationContext} instance
     *            provided by Jira
     * @param emailFormatter
     *            reference to {@link EmailFormatter} instance provided by Jira
     * @param groupPermissionChecker
     *            reference to {@link GroupPermissionChecker} instance provided
     *            by Jira
     * @param userMgr
     *            reference to {@link UserManager} instance provided by Jira
     * @param sharingConfig
     *            reference to {@link IPortalPageSharingConfiguration}
     *            propagated from Jira
     */
    public ConfigureSharedPortalPages(
            final IDashboardSharingPortalManager portalMgr,
            final JiraAuthenticationContext authenticationContext,
            final EmailFormatter emailFormatter,
            final GroupPermissionChecker groupPermissionChecker,
            final UserManager userMgr,
            final IPortalPageSharingConfiguration sharingConfig) {
        super(portalMgr, authenticationContext, emailFormatter,
                groupPermissionChecker);
        this.portalManager = portalMgr;
        this.userManager = userMgr;
        this.configuration = sharingConfig;
    }

    /**
     * Returns {@link List} of view representations of portal pages owned by
     * currently logged user.
     * 
     * @return {@link List} of view representations of portal pages owned by
     *         currently logged user
     */
    public List<SharedPortalPage> getOwnDashboardPages() {
        try {
            Collection<PortalPageConfiguration> ownPortalPages = this.portalManager
                    .getOwnPortalPageConfigurations(getUser()).values();

            return transformToSharedPortalPages(ownPortalPages);
        } catch (PortletConfigurationException e) {
            addErrorMessage(UNABLE_TO_GET_OWN_PORTAL_PAGES);
        }
        return null;
    }

    /**
     * Returns instance of {@link PortalManager} referenced by this instance of
     * action.
     * 
     * @return instance of {@link PortalManager} referenced by this instance of
     *         action
     */
    public PortalManager getPortalManager() {
        return portalManager;
    }

    /**
     * Returns {@link List} of view representations of portal pages shared to
     * currently logged user.
     * 
     * @return {@link List} of view representations of portal pages shared to
     *         currently logged user
     */
    public List<SharedPortalPage> getSharedDashboardPages() {
        try {
            Collection<PortalPageConfiguration> sharedPortalPages = this.portalManager
                    .getSharedPortalPageConfigurations(getUser()).values();
            return transformToSharedPortalPages(sharedPortalPages);
        } catch (PortletConfigurationException e) {
            addErrorMessage(UNABLE_TO_GET_SHARED_PORTAL_PAGES);
        }
        return null;
    }

    /**
     * Transforms {@link Collection} of {@link PortalPageConfiguration}s to
     * {@link List} of {@link SharePortalPage}s.
     * 
     * @param portalPages
     *            portal pages to be transformed
     * @return transformed shared portal page views
     */
    protected List<SharedPortalPage> transformToSharedPortalPages(
            final Collection<PortalPageConfiguration> portalPages) {
        List<SharedPortalPage> sharedPortalPages = new ArrayList<SharedPortalPage>();

        for (PortalPageConfiguration portalPage : portalPages) {

            SharedPortalPage sharedPortalPage = transformToSharedPortalPage(portalPage);
            sharedPortalPages.add(sharedPortalPage);
        }

        return sharedPortalPages;
    }

    /**
     * Transforms standard Jira {@link PortalPageConfiguration} object to
     * {@link SharePortalPage} object from view domain model.
     * 
     * @param portalPage
     *            portal page configuration to be transformed to view domain
     *            model
     * @return view representation of <code>portalPage</code>
     */
    protected SharedPortalPage transformToSharedPortalPage(
            final PortalPageConfiguration portalPage) {
        User author = null;
        String group = null;
        boolean shared = configuration.isShared(portalPage.getId());
        if (shared) {
            ISharedPortalPage sharedDashboard = configuration
                    .getSharedPortalPage(portalPage.getId());

            String authorName = sharedDashboard.getAuthor();
            group = sharedDashboard.getGroupName();
            if (group != null && group.length() == 0) {
                group = null;
            }

            try {
                author = getUser(authorName);
            } catch (EntityNotFoundException e) {
                LOG.warn("Unable to find user '" + authorName
                        + "', author of '" + portalPage.getId()
                        + "' portal page.");
            }
        } else {
            author = this.getUser();
        }
        return new SharedPortalPage(portalPage, this.getUser(), author, shared,
                group);
    }

    /**
     * Resolves and returns {@link User} with specified <code>userName</code>.
     * 
     * @param userName
     *            user name of the user we want to get
     * @return resolved user
     * @throws EntityNotFoundException
     *             thrown for same reason like
     *             {@link UserManager#getUser(String)}
     */
    protected User getUser(final String userName)
            throws EntityNotFoundException {
        return userManager.getUser(userName);
    }

    /**
     * Representation of portal page for UI. This implementation simply wraps
     * {@link PortalPageConfiguration} and adds additional functionality related
     * to portal page sharing.
     */
    public static class SharedPortalPage {

        /**
         * Author of the page.
         */
        private final User author;

        /**
         * Name of group to which the portal page is shared. Should be
         * <code>null</code> when not shared to group.
         */
        private final String group;

        /**
         * Jira {@link PortalPageConfiguration} represented by this
         * {@link SharePortalPage}.
         */
        private final PortalPageConfiguration portalPage;

        /**
         * Currently logged user.
         */
        private final User user;

        /**
         * Is page shared or not.
         */
        private final boolean shared;

        /**
         * Constructor for {@link SharePortalPage}.
         * 
         * @param portalPageConfig
         *            Jira {@link PortalPageConfiguration} represented by this
         *            {@link SharePortalPage}
         * @param loggedUser
         *            currently logged user
         * @param pageAuthor
         *            author of the page
         * @param sharedFlag
         *            is page shared or not
         * @param groupName
         *            name of group to which the portal page is shared. Should
         *            be <code>null</code> when not shared to group
         */
        public SharedPortalPage(final PortalPageConfiguration portalPageConfig,
                final User loggedUser, final User pageAuthor,
                final boolean sharedFlag, final String groupName) {
            super();
            this.portalPage = portalPageConfig;
            this.user = loggedUser;
            this.author = pageAuthor;
            this.shared = sharedFlag;
            this.group = groupName;
        }

        /**
         * Returns instance of {@link User} class representing author of the
         * portal page.
         * 
         * @return instance of {@link User} class representing author of the
         *         portal page
         */
        public User getAuthor() {
            return author;
        }

        /**
         * Returns description of the portal page.
         * 
         * @return description of the portal page
         */
        public String getDescription() {
            return portalPage.getDescription();
        }

        /**
         * Returns name of group for which the portal page is shared.
         * 
         * @return name of group for which the portal page is shared
         */
        public String getGroup() {
            return this.group;
        }

        /**
         * Returns ID of the portal page.
         * 
         * @return ID of the portal page
         */
        public Long getId() {
            return portalPage.getId();
        }

        /**
         * Returns name of the portal page.
         * 
         * @return name of the portal page
         */
        public String getPageName() {
            return portalPage.getPageName();
        }

        /**
         * Returns instance of {@link User} class representing currently logged
         * user.
         * 
         * @return instance of {@link User} class representing currently logged
         *         user
         */
        public User getUser() {
            return user;
        }

        /**
         * Informs whether the portal page is default or not.
         * 
         * @return true if the portal page is default. Otherwise returns false.
         */
        public boolean isDefault() {
            return portalPage.isDefault();
        }

        /**
         * Returns <code>true</code> if the portal page represented by this
         * {@link SharePortalPage} is shared, otherwise false.
         * 
         * @return <code>true</code> if the portal page represented by this
         *         {@link SharePortalPage} is shared, otherwise false
         */
        public boolean isShared() {
            return shared;
        }
    }
}
